package crons

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"github.com/spf13/viper"
	"go.didapinche.com/foundation/plat-echo/app/ops/models"
	"go.didapinche.com/foundation/plat-echo/app/ops/models/request"
	"go.didapinche.com/foundation/plat-echo/app/ops/repositories"
	"go.didapinche.com/foundation/plat-echo/app/ops/services"
	"go.didapinche.com/foundation/plat-echo/pkg/dingding"
	"go.didapinche.com/foundation/plat-echo/pkg/utils/data"
	"go.didapinche.com/goapi/uic_service_api"
	time2 "go.didapinche.com/time"
	"go.uber.org/zap"
	"strconv"
	"strings"
	"text/template"
	"time"
)

const Title = "%s 告警日报"

const DayTitle = "%s 告警日报"

const DayMessage = `
### {{.date}}  告警日报
{{$levelSlaNum := .levelSlaNum}}
#### L0 SLA：{{$levelSlaNum}}%
#### L0 应用数：{{.appCount}}
#### L0 接口数：{{.apiCount}}
---
#### L0 TOP 10 < 100% 应用：
{{$appSla := .appSla}}
{{range $_,$appSlaOne := $appSla}}
##### 应用名：[{{$appSlaOne.AppName}}](http://pass.didapinche.com/echo/v2/full/graph/{{$appSlaOne.AppID}}/{{$appSlaOne.AppName}}?level=L0)
##### sla：{{$appSlaOne.Sla}}
##### 负责人：{{range $_,$owner := $appSlaOne.Users}}[@{{$owner}}](){{end}}
---
{{end}}
> [查看详情]({{.appUrl}})
---
#### L0 TOP 10 < 100% 接口：
{{$apiSla := .apiSla}}
{{range $_,$apiSlaOne := $apiSla}}
##### 应用名：{{$apiSlaOne.AppName}}
##### 接口名：[{{$apiSlaOne.Method}}](http://pass.didapinche.com/echo/v2/main/interface/detail/{{$apiSlaOne.ApiID}})
##### sla：{{$apiSlaOne.Sla}}%
##### 负责人：{{range $_,$owner := $apiSlaOne.Users}}[@{{$owner}}](){{end}}
---
{{end}}
> [查看详情]({{.apiUrl}})
`

type AlertDailyStatJob struct {
	logger       *zap.Logger
	service      dingding.DingDingService
	appService   services.AppService
	apiService   services.ApiDataService
	dingDingRepo repositories.DingdingRepository
	uicService   uic_service_api.TChanUicService
}

func NewAlertDailyStatJob(logger *zap.Logger,
	service dingding.DingDingService,
	appService services.AppService,
	apiService services.ApiDataService,
	dingDingRepo repositories.DingdingRepository,
	uicService uic_service_api.TChanUicService) *AlertDailyStatJob {
	job := &AlertDailyStatJob{
		apiService:   apiService,
		appService:   appService,
		logger:       logger,
		service:      service,
		dingDingRepo: dingDingRepo,
		uicService:   uicService,
	}
	return job
}

func (a *AlertDailyStatJob) Run() {
	//时间
	now := time.Now()
	start := data.GetYesterdayStart(now)
	date := data.GetDate(start)

	ctx := context.Background()
	//目标钉钉群
	dings, _, err := a.dingDingRepo.Find(ctx, &models.DingDing{Name: "Echo-SLA"})
	if err != nil {
		a.logger.Error("call dingDingRepo.Find() error", zap.Error(err))
		return
	}

	if len(dings) == 0 {
		a.logger.Error("钉钉群 Echo-SLA 不存在", zap.Error(errors.New("钉钉群 Echo-SLA 不存在")))
		return
	}

	// api - sla
	appSlaMap, appCount, err := a.appService.Find(ctx, &request.SlaQuery{Level: 1, PageNum: 1, PageSize: 10, Start: time2.Time{time.Now().AddDate(0, 0, -1)}.String(), End: time2.Time{time.Now()}.String(), Sort: "sla", Order: 1})
	if err != nil {
		a.logger.Error(fmt.Sprintf("call apiDataRepo.GetStatistics() error"), zap.Error(err))
	}

	apiSlaMap, apiCount, err := a.apiService.Find(ctx, &request.ApiSlaRequest{Level: 1, PageNum: 1, PageSize: 10, Start: time2.Time{time.Now().AddDate(0, 0, -1)}.String(), End: time2.Time{time.Now()}.String(), Order: "sla desc", TemplateType: 1})
	if err != nil {
		a.logger.Error(fmt.Sprintf("call apiDataRepo.GetStatistics() error"), zap.Error(err))
	}

	if err != nil {
		a.logger.Error(fmt.Sprintf("call apiDataRepo.GetStatistics() error"), zap.Error(err))
	}
	appSla := make([]*models.ApiData, 0)
	for _, appMap := range appSlaMap {
		app := new(models.ApiData)
		app.AppName = appMap["app_name"].(string)
		app.AppID = appMap["app_id"].(uint64)
		app.Sla = appMap["sla"].(string)
		if strings.Contains(app.Sla, "100") {
			break
		}
		app.Users = appMap["users"].([]string)
		appSla = append(appSla, app)
	}
	apiSla := make([]*models.ApiData, 00)
	for _, apiMap := range apiSlaMap {
		api := new(models.ApiData)
		api.AppName = apiMap.AppName
		api.AppID = apiMap.AppID
		api.Sla = strconv.Itoa(int(apiMap.SLA))
		users := make([]string, 0)
		for _, u := range apiMap.GetOwners() {
			users = append(users, u.UserName)
		}
		if apiMap.SLA == 100 {
			break
		}
		api.Users = users
		api.ApiID = apiMap.ApiID
		if apiMap.HttpMethod != "" {
			api.Method = apiMap.HttpMethod + ":" + apiMap.HttpPath
		} else {
			api.Method = apiMap.ZeusService + ":" + apiMap.ZeusMethod
		}
		apiSla = append(apiSla, api)
	}

	// level - sla
	levelSla, err := a.apiService.FindSlaStat(ctx, &request.OverviewReq{Start: time2.Time{time.Now().AddDate(0, 0, -1)}.String(), End: time2.Time{time.Now()}.String(), GroupID: "group-2"})
	if err != nil {
		a.logger.Error(fmt.Sprintf("call apiDataRepo.GetStatistics() error"), zap.Error(err))
	}
	var levelSlaNum float64
	if levelSla != nil && levelSla.L0 != nil {
		{
			levelSlaNum = levelSla.L0.SLA
			if levelSlaNum == 0 {
				levelSlaNum = 100
			}
		}
	}

	t, err := template.New("temp").Parse(DayMessage)
	if err != nil {
		a.logger.Error("parse message template error", zap.Error(err))
		return
	}

	var buf bytes.Buffer
	err = t.Execute(&buf, map[string]interface{}{
		"appSla":      appSla,
		"apiSla":      apiSla,
		"date":        date,
		"appUrl":      viper.GetString("appUrl"),
		"apiUrl":      viper.GetString("apiUrl"),
		"appCount":    appCount,
		"apiCount":    apiCount,
		"levelSlaNum": levelSlaNum,
	})
	msg := &dingding.DingMessage{
		MessageType: "markdown",
		Markdown: dingding.Markdown{
			Title: fmt.Sprintf(DayTitle, date),
			Text:  buf.String(),
		},
		At: dingding.At{
			IsAtAll: false,
		},
	}

	mobiles := make([]string, 0)
	for _, tmp := range appSla {
		mobiles = append(mobiles, tmp.Users...)
	}
	for _, tmp := range apiSla {
		mobiles = append(mobiles, tmp.Users...)
	}

	msg.At.AtMobiles = mobiles

	for _, ding := range dings {
		err := a.service.SendMessage(ding.Token, msg)
		if err != nil {
			a.logger.Error("err:", zap.Error(err))
		}
	}
}

func (a *AlertDailyStatJob) Cron() string {
	return "0 0 9 * * ?"
}

func (a *AlertDailyStatJob) Name() string {
	return "alert_daily_stat_job"
}
